﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

#pragma once
#include "GcmpApiFoundation.h"
#include "WeakPtr.h"

namespace gdmp {
    namespace api {
        /// <summary>
        /// 1. 存储托管对象持有的C++指针
        /// 2. 当对象释放时会自动解除托管对象的占用
        /// 3. GCHandle在使用上类似std::unique_ptr
        /// 4. 程序退出时C#会优先释放资源
        /// </summary>
        template <typename T>
        class GCHandle final
        {
        public:
            GCHandle() noexcept = default;
            GCHandle(std::nullptr_t) noexcept {}
            explicit GCHandle(T* ptr) noexcept : m_ptr(ptr) {}

            GCHandle(const GCHandle&) = delete;
            GCHandle& operator=(const GCHandle&) = delete;

            ~GCHandle() noexcept
            {
                reset(nullptr);
            }
            GCHandle& operator=(std::nullptr_t)
            {
                this->reset(nullptr);
                return *this;
            }
            GCHandle(GCHandle&& rhx) noexcept
            {
                auto p = rhx.get();
                rhx.m_ptr = nullptr;
                reset(p);
            }
            GCHandle& operator=(GCHandle&& rhx) noexcept
            {
                auto p = rhx.get();
                rhx.m_ptr = nullptr;
                reset(p);
                return *this;
            }
            const T* get() const noexcept { return m_ptr.Get(); }
            T* get() noexcept { return m_ptr.Get(); }
            const T* operator->() const noexcept { return get(); }
            T* operator->() noexcept { return get(); }
            explicit operator bool() const noexcept { return m_ptr; }
        private:
            void reset(T* ptr) noexcept
            {
                T* old = m_ptr.Get();
                m_ptr.Reset(ptr);
                if (old) {
                    delete old;
                    old = nullptr;
                }
            }

            gcmp::WeakPtr<T> m_ptr;
        };
    }
}
